`define OP_AND   8'h00
`define OP_ANDI  8'h01
`define OP_NAND  8'h02
`define OP_NANDI 8'h03
`define OP_OR    8'h04
`define OP_ORI   8'h05
`define OP_NOR   8'h06
`define OP_NORI  8'h07
`define OP_XOR   8'h08
`define OP_XORI  8'h09
`define OP_EQ    8'h10
`define OP_EQI   8'h11
`define OP_NE    8'h12
`define OP_NEI   8'h13
`define OP_LT    8'h14
`define OP_LTI   8'h15
`define OP_LE    8'h16
`define OP_LEI   8'h17
`define OP_ADD   8'h20
`define OP_ADDI  8'h21
`define OP_SUB   8'h22
`define OP_SUBI  8'h23
`define OP_LW    8'h40
`define OP_SW    8'h60
`define OP_JRL   8'h80
`define OP_BEQ   8'h90
`define OP_BEQZ  8'h91
`define OP_BNE   8'h92
`define OP_BNEZ  8'h93

`define OP_BITS  IWORD[31:24]
`define RD_BITS  IWORD[23:20]
`define RS_BITS  IWORD[19:16]
`define RT_BITS  IWORD[15:12]
`define IM_BITS  IWORD[15:00]

`define RX_BITS  4'bXXXX

module CtlRReg(IWORD,RREGNO1,RREGNO2);
  input  wire [31:0] IWORD;
  output wire [3:0] RREGNO1,RREGNO2;
  wire reg1rd=IWORD[31]&&IWORD[28]&&IWORD[24];
  assign RREGNO1=reg1rd?`RD_BITS:`RS_BITS;
  wire reg2rt=(!IWORD[31])&&(!IWORD[30]);
  assign RREGNO2=reg2rt?`RT_BITS:`RD_BITS;
endmodule

//DONE MAY NEED DEBUGGING CHECK IF INSTRUCTIONS THAT USE RD ARE ACTUALLY SELECTED
module CtlWReg(IWORD,WREGNO,WRREG);
  input  wire [31:0] IWORD;
  output  reg [3:0] WREGNO;
  output  reg WRREG;
	
	always @(IWORD) begin
		case(`OP_BITS)
			`OP_NAND,`OP_OR,`OP_NOR,`OP_XOR,
			`OP_EQ,`OP_NE,`OP_LT,`OP_LE,
			`OP_ADD,`OP_SUB,
			`OP_ANDI,`OP_NANDI,`OP_ORI,`OP_NORI,`OP_XORI,
			`OP_EQI,`OP_NEI,`OP_LTI,`OP_LEI,
			`OP_ADDI,`OP_SUBI,
			`OP_LW,
			`OP_JRL: 
				{WRREG, WREGNO}={1'b1,`RD_BITS};

			`OP_BEQZ,`OP_BNEZ, `OP_BNE, `OP_BEQ, `OP_SW: 
			 	{WRREG, WREGNO}={1'b0,`RX_BITS};
			`OP_AND: begin
				if(IWORD[31:0]==32'b0)
					{WRREG, WREGNO}={1'b0,`RX_BITS};
				else 
					{WRREG, WREGNO}={1'b1,`RD_BITS};
			 end
		default:
			{WRREG, WREGNO}={1'b0,`RX_BITS};
		endcase
	end
  	/*always @(IWORD) begin
		WRREG=1'b0;
		//if it's an instruction that uses WB, generate the approperate signals
		//first checks if it is an ALU op that always WB, then checks the other 2 instructions
		if (IWORD[31:0]==32'b0) begin
			WRREG=1'b0;
			WREGNO=`RX_BITS;
		end else if (IWORD[31:30]==2'b00) begin
			WRREG=1'b1;
			WREGNO=`RD_BITS;
		end else if (`OP_BITS==`OP_JRL) begin
			WRREG=1'b1;
			WREGNO=`RD_BITS;
		end else if (`OP_BITS==`OP_LW) begin
			WRREG=1'b1;
			WREGNO=`RD_BITS;
		end else begin
			WRREG=1'b0;
			WREGNO=`RX_BITS;
		end
	end*/
  
/*
	DONE DEBUG POINT
   Put your code to generate WREGNO and WRREG here
*/

endmodule

//DONE MAY NEED DEBUGGING CHECK IF SIGN EXTEND AND x4 SIGN EXTEND ARE WORKING ON THE RIGHT INSTRUCTIONS
module CtlImm(IWORD,IMMVAL);
  parameter DBITS;
  input  wire [31:0] IWORD;
  output reg [31:0] IMMVAL;
	always@(IWORD)begin
		IMMVAL={{(DBITS-16){IWORD[15]}},`IM_BITS};
		if(IWORD[31:30]==2'b00)//sign extend for alu ops
			IMMVAL=IMMVAL;
		else if (IWORD[31:30]==2'b01)
			IMMVAL=IMMVAL;
		else if (IWORD[31:30]==2'b10)
			IMMVAL=IMMVAL<<2;
		else //sign extendx4
			IMMVAL=IMMVAL;
			
		/*(`OP_BITS==`OP_LW)
			IMMVAL=IMMVAL;
		else if (`OP_BITS==`OP_SW)
			IMMVAL=IMMVAL;*/

	end
endmodule

module CtlALUIn(IWORD,ALUIN2Z,ALUIN2I);
  input  wire [31:0] IWORD;
  output reg  ALUIN2Z,ALUIN2I;
  always @(IWORD) begin
    case(`OP_BITS)
    `OP_AND,`OP_NAND,`OP_OR,`OP_NOR,`OP_XOR,
    `OP_EQ,`OP_NE,`OP_LT,`OP_LE,
    `OP_ADD,`OP_SUB,
    `OP_BEQ,`OP_BNE:
      {ALUIN2Z,ALUIN2I}=2'bX0;
    `OP_ANDI,`OP_NANDI,`OP_ORI,`OP_NORI,`OP_XORI,
    `OP_EQI,`OP_NEI,`OP_LTI,`OP_LEI,
    `OP_ADDI,`OP_SUBI,
    `OP_LW,`OP_SW,
    `OP_JRL:
      {ALUIN2Z,ALUIN2I}=2'b01;
    `OP_BEQZ,`OP_BNEZ:
      {ALUIN2Z,ALUIN2I}=2'b11;
    default:
      {ALUIN2Z,ALUIN2I}=2'bXX;
    endcase
  end
endmodule

//DONE MAY NEED DEBUGGING
module CtlALU(IWORD,
              ALULOG,LOGAND,LOGOR,LOGXOR,LOGNOT,
              ADDSUB,
              ALUCMP,CMPEQ,CMPLT,CMPNOT,
              ALUARI);
	input  wire [31:0] IWORD;
	output reg  ALULOG,LOGAND,LOGOR,LOGXOR,LOGNOT,
				ADDSUB,
				ALUCMP,CMPEQ,CMPLT,CMPNOT,
				ALUARI;         
	always @(IWORD) begin
		{ALULOG,LOGAND,LOGOR,LOGXOR,LOGNOT,ADDSUB,ALUCMP,CMPEQ,CMPLT,CMPNOT,ALUARI} = {1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0};
		case(`OP_BITS)
		//pretty sure logic function are correct- tested these on a different file for operations
			`OP_AND, `OP_ANDI: {ALULOG, LOGAND} = {1'b1, 1'b1};
			`OP_NAND,`OP_NANDI: {ALULOG, LOGAND, LOGNOT} = {1'b1, 1'b1, 1'b1};
			`OP_OR, `OP_ORI: {ALULOG, LOGOR} = {1'b1, 1'b1};
			`OP_NOR, `OP_NORI: {ALULOG, LOGOR, LOGNOT} = {1'b1, 1'b1, 1'b1};
			`OP_XOR, `OP_XORI: {ALULOG, LOGXOR} = {1'b1, 1'b1};
			`OP_EQ, `OP_EQI, `OP_BEQ,`OP_BEQZ: {ALUCMP, CMPEQ} = {1'b1, 1'b1};
			`OP_NE, `OP_NEI, `OP_BNE,`OP_BNEZ: {ALUCMP, CMPEQ, CMPNOT} = {1'b1, 1'b1, 1'b1};
			`OP_LT, `OP_LTI: {ALUCMP, ADDSUB, CMPLT} = {1'b1, 1'b1, 1'b1};
			//works
			`OP_LE, `OP_LEI: {ALUCMP, ADDSUB, CMPLT, CMPEQ} = {1'b1, 1'b1, 1'b1, 1'b1};
			`OP_ADD, `OP_ADDI, `OP_LW, `OP_SW, `OP_JRL: {ADDSUB, ALUARI} = {1'b0, 1'b1};
			`OP_SUB, `OP_SUBI: {ADDSUB, ALUARI} = {1'b1, 1'b1};
		default:
			  {ALULOG,LOGAND,LOGOR,LOGXOR,LOGNOT,ADDSUB,ALUCMP,CMPEQ,CMPLT,CMPNOT,ALUARI} = {1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0};
		endcase
	end
endmodule

module CtlWMem(IWORD,WMEM,RMEM);
  input  wire [31:0] IWORD;
  output reg WMEM,RMEM;
  always @(IWORD) begin
    case(`OP_BITS)
    `OP_SW:
      {WMEM,RMEM}={1'b1,1'b0};
    `OP_LW:
      {WMEM,RMEM}={1'b0,1'b1};
    `OP_AND,`OP_ANDI,`OP_NAND,`OP_NANDI,
    `OP_OR,`OP_ORI,`OP_NOR,`OP_NORI,
    `OP_XOR,`OP_XORI,
    `OP_EQ,`OP_EQI,`OP_NE,`OP_NEI,
    `OP_LT,`OP_LTI,`OP_LE,`OP_LEI,
    `OP_ADD,`OP_ADDI,`OP_SUB,`OP_SUBI,
    `OP_JRL:          
      {WMEM,RMEM}={1'b0,1'b0};
    default:
      {WMEM,RMEM}={1'b0,1'b0};
    endcase
  end
endmodule

module BraCtl(IWORD,ISBRANCH,ISJUMP,SAVEPC);
  input  wire [31:0] IWORD;
  output reg ISBRANCH,ISJUMP,SAVEPC;
  
  always @(IWORD) begin
  	{ISBRANCH,ISJUMP,SAVEPC}={1'b0,1'b0,1'b0};
	case(`OP_BITS)
	`OP_BEQ, `OP_BEQZ, `OP_BNE, `OP_BNEZ: {ISBRANCH,ISJUMP,SAVEPC}={1'b1,1'b0,1'b0};
	`OP_JRL: {ISBRANCH,ISJUMP,SAVEPC}={1'b0,1'b1,1'b1};
	default:
	  {ISBRANCH,ISJUMP,SAVEPC}={1'b0,1'b0,1'b0};
	endcase
  end
endmodule

module Assign3(SW,KEY,/*LEDR,LEDG,*/HEX0,HEX1,HEX2,HEX3,CLOCK_50); 
  input  [9:0] SW;
  input  [3:0] KEY;
  input  CLOCK_50;
  //output [9:0] LEDR;
 // output [7:0] LEDG;
  output [6:0] HEX0,HEX1,HEX2,HEX3;

  wire [6:0] digit0,digit1,digit2,digit3;

  wire clk, lock;
/*
  Use the MegaWizard to create a PLL object called "Pll" so this can work
*/
  //wire lock=1;
  //wire clk=CLOCK_50;
   //wire clk = !KEY[0];
	PLLAssign3	PLLAssign3_inst (
	.inclk0 ( CLOCK_50 ),
	.c0 ( clk ),
	.locked ( lock )
	);


  //Pll pll_inst(.inclk0(CLOCK_50),.c0(clk),.locked(lock));
  
  wire [3:0] keys=KEY;
  wire [9:0] switches=SW;

  assign {HEX0,HEX1,HEX2,HEX3}={digit0,digit1,digit2,digit3};

  parameter DBITS=32;

  // Program Counter (value used in F stage, updated using inputs from F and A stages)
  reg  [(DBITS-1):0] PC=32'h400;//400;
  // We update the PC only if clock signal is locked
  // Note that jumps and taken branches update the PC two cycles late, so the two instructions
  // that follow a jump or taken branch are executed anyway (effectively, we have two delay slots)
  always @(posedge clk) if(lock) begin
    if(usebtarg_A)
      PC<=PCBT_A;
    else if(usejtarg_A)
      PC<=PCJT_A;
    else
      PC<=PC4_F;
  end
  wire [(DBITS-1):0] PC_F=PC;
  // Register file, read in R stage, written in W stage
  RegFile  #(.DBITS(DBITS),.ABITS(4),.MFILE("Assign2R.mif"))
    regFile(.RADDR1(rregno1_R),.DOUT1(regout1_R),
            .RADDR2(rregno2_R),.DOUT2(regout2_R),
            .WADDR(wregno_W),.DIN(regval_W),
            .WE(wrreg_W),
            .CLK(clk));
  MemSys #(.DBITS(DBITS),.RABITS(13),.MFILE("Assign3.mif"))
    memSys(.IAddr(PC_F),.IOut(inst_F),
           .DAddr(aluout_M),.DIn(regout2_M),.DOut(memout_M),.DWE(wmem_M),
           .CLK(clk),
           .KEY(keys),.SW(switches),
           .HEX0(digit0),
           .HEX1(digit1),
           .HEX2(digit2),
           .HEX3(digit3));

  // PC+4 generated in the F stage (used in F to update PC, also used for branch and JRL insts in later stages)
  wire [(DBITS-1):0] PC4_F=PC_F+32'd4;
  // Instruction word, generated (from MemSys, see above) in the FE stage
  wire [(DBITS-1):0] inst_F;
  // Register numbers for reading generated and used in F stage
  wire [3:0] rregno1_F,rregno2_F;
  CtlRReg ctlRReg(.IWORD(inst_F),.RREGNO1(rregno1_F),.RREGNO2(rregno2_F));
  
  // Pipeline registers between F and R stages
  reg [(DBITS-1):0] inst_R=32'b0,PC4_R;
  reg [3:0] rregno1_R,rregno2_R;
  // Get new F->R signals each locked clock cycle
  always @(posedge clk) if(lock) begin
    {inst_R,PC4_R,rregno1_R,rregno2_R}<={inst_F,PC4_F,rregno1_F,rregno2_F};
  end

  // Register outputs generated in R stage (from RegFile, see above), used in subsequent stages
  wire [(DBITS-1):0] regout1_R,regout2_R;
  // Immediate value sign-extension and *4 (if needed) is done in R and used in R (for ALU) and A (for branches)
  wire [(DBITS-1):0] immval_R;
  CtlImm #(.DBITS(DBITS)) ctlImm(.IWORD(inst_R),.IMMVAL(immval_R));

  // Control for the second ALU input value (reg, imm, or zero) is generated in R, used in R
  // aluin2i decides between register and non-register value for ALU input 2; it is used in A
  // aluin2z selects between sxt(imm) and zero for the non-reg value; it is used in R
  // Note that aluin2z matters only when aluin2i is 1
  wire aluin2z_R,aluin2i_R;
  CtlALUIn ctlALUIn(.IWORD(inst_R),.ALUIN2Z(aluin2z_R),.ALUIN2I(aluin2i_R));
  // If non-reg used as second ALU input value, it is zero or sxt(imm). We select between them in R
  // The result of this selection goes to A stage, where we select between it and regout2
  wire [(DBITS-1):0] aluimm_R=aluin2z_R?32'd0:immval_R;

  // ALU function controls generated in R, used in A stage
  // Logic result enabled if alulog is 1
  // Logic operation selected by aluand,aluor,aluxor
  // Logic result inverted if lognot is 1
  wire alulog_R,logand_R,logor_R,logxor_R,lognot_R;
  // Arithmetic and comparison operations use the adder/subtractor
  // It adds if addsub is 0, subtracts otherwise
  wire addsub_R;
  // Comparison result enabled if alucmp is 1
  // Comparison result is eq, lt, or both (le)
  // Comparison result inverted if cmpnot_g is 1
  wire alucmp_R,cmpeq_R,cmplt_R,cmpnot_R;
  // Enables arithmetic result (ALU result comes directly from the adder/subtractor)
  wire aluari_R;
  CtlALU ctlALU(.IWORD(inst_R),
                .ALULOG(alulog_R),.LOGAND(logand_R),.LOGOR(logor_R),.LOGXOR(logxor_R),.LOGNOT(lognot_R),
                .ADDSUB(addsub_R),
                .ALUCMP(alucmp_R),.CMPEQ(cmpeq_R),.CMPLT(cmplt_R),.CMPNOT(cmpnot_R),
                .ALUARI(aluari_R));

  // Branch/jump control signals generated in R, used in A stage
  wire isbranch_R,isjump_R,savepc_R;
  BraCtl braCtl(.IWORD(inst_R),.ISBRANCH(isbranch_R),.ISJUMP(isjump_R),.SAVEPC(savepc_R));

  // Memory read and write control (generated in R, used in M and W stages)
  wire wmem_R,rmem_R;
  CtlWMem ctlWMem(.IWORD(inst_R),.WMEM(wmem_R),.RMEM(rmem_R));

  // Register write control, generated in R and used in W stages
  wire [3:0] wregno_R;
  wire wrreg_R;
  CtlWReg ctlWReg(.IWORD(inst_R),.WREGNO(wregno_R),.WRREG(wrreg_R));
  
  //A <= R pipeline
  
  //generating all the wires
    reg [(DBITS-1):0] PC4_A, regout1_A, regout2_A, immval_A, aluimm_A;
	reg aluin2i_A, alulog_A, logand_A, logor_A, logxor_A, lognot_A;
	reg addsub_A, alucmp_A, cmpeq_A, cmplt_A, cmpnot_A;
	reg aluari_A, isbranch_A, isjump_A, savepc_A;
	reg wmem_A, rmem_A, wrreg_A;
	reg [3:0] wregno_A;
	//reg [31:0] inst_A; //for debugging
  
  always @(posedge clk) if(lock) begin
	{regout1_A,	regout2_A,	immval_A,	aluin2i_A	} <= {regout1_R,	regout2_R,	immval_R,	aluin2i_R	};
	{aluimm_A,	alulog_A,	logand_A,	logor_A		} <= {aluimm_R,		alulog_R, 	logand_R,	logor_R		};
	{logxor_A,	lognot_A,	addsub_A,	alucmp_A	} <= {logxor_R,		lognot_R,	addsub_R,	alucmp_R	};
	{cmpeq_A,	cmplt_A,	cmpnot_A,	aluari_A	} <= {cmpeq_R,		cmplt_R,	cmpnot_R,	aluari_R	};
	{isbranch_A,isjump_A,	savepc_A,	wmem_A		} <= {isbranch_R,	isjump_R,	savepc_R,	wmem_R		};
	{rmem_A, 	wregno_A,	wrreg_A, 	PC4_A		} <= {rmem_R,		wregno_R,	wrreg_R,	PC4_R		};
	//debug line
	//inst_A<=inst_R;
  end

/*
  The code given below is the ALU.
  If you do cannot figure out how to generate control signals for it,
  you can make your own ALU and generate control signals for that.
*/

  // ALU input values (generated and used in A stage)
  wire [(DBITS-1):0] aluin1_A=regout1_A;
  wire [(DBITS-1):0] aluin2_A=aluin2i_A?aluimm_A:regout2_A;
  // The ALU generates its result in the A stage, it is used in A, M,and W stages
  // Generate logic result (or zero if  select it or ignore it)
  wire [(DBITS-1):0] andout_A={DBITS{logand_A}}&(aluin1_A&aluin2_A);
  wire [(DBITS-1):0] orout_A ={DBITS{logor_A }}&(aluin1_A|aluin2_A);
  wire [(DBITS-1):0] xorout_A={DBITS{logxor_A}}&(aluin1_A^aluin2_A);
  wire [(DBITS-1):0] logtmp_A=(andout_A|orout_A|xorout_A);
  wire [(DBITS-1):0] logres_A=lognot_A?(~logtmp_A):logtmp_A;
  wire [(DBITS-1):0] logout_A=logres_A&{DBITS{alulog_A}};
  // This is our adder/subtractor (if subtract, invert 2nd input, add 1)
  wire [(DBITS-1):0] arires_A=
    aluin1_A+(addsub_A?(~aluin2_A):aluin2_A)+addsub_A;
  wire [(DBITS-1):0] ariout_A=arires_A&{DBITS{aluari_A}};
  // Generate comparison result (lt uses subtration result, so addsub must be 1 for lt or lte)
  wire eqout_A=cmpeq_A&&(aluin1_A==aluin2_A);
  wire ltout_A=cmplt_A&&arires_A[31];
  wire cmptmp_A=eqout_A||ltout_A;
  wire cmpres_A=cmpnot_A?(!cmptmp_A):cmptmp_A;
  wire [(DBITS-1):0] cmpout_A={{(DBITS-1){1'b0}},cmpres_A&&alucmp_A};
  // Final ALU result
  wire [(DBITS-1):0] aluout_A=logout_A|ariout_A|cmpout_A;
  
  // Put your code here to generate these signals:
  // PCBT_A (target address for a branch, will be used only if this is a taken branch)
  wire [(DBITS-1):0] PCBT_A = (PC4_A+immval_A);
  
  //PCJT_A (target address for a jump, will be used only if this is a jump)
  wire [(DBITS-1):0] PCJT_A = aluout_A;
  
  //usebtarg_A (one-bit signal that is set to 1 if this is a taken branch)
  wire usebtarg_A = isbranch_A?aluout_A[0]:1'b0;
  //usejtarg_A (one-bit signal that is set to 1 if this is a jump)
  wire usejtarg_A = isjump_A;
  
  //registers from A to M
    //generating all the wires
	reg [(DBITS-1):0] PC4_M, aluout_M, regout2_M;
	reg savepc_M, wrreg_M, wmem_M, rmem_M;
	reg [3:0] wregno_M;
    always @(posedge clk) if(lock) begin
		{PC4_M,		aluout_M,	savepc_M,	wregno_M	} <= {PC4_A,	aluout_A,	savepc_A,	wregno_A	};
		{wrreg_M,	wmem_M, 	regout2_M,	rmem_M		} <= {wrreg_A,	wmem_A,		regout2_A,	rmem_A		};
	end

  // Memory output generated in M, used in W
  wire [(DBITS-1):0] memout_M;//=rmem_M?memout_M:32'bZ;
  // For non-memory results, choose between ALU result and PC+4
  wire [(DBITS-1):0] nonmem_M=savepc_M?PC4_M:aluout_M;

  //registers from M to W
    //generating all the wires
	reg [(DBITS-1):0] memout_W, nonmem_W;
	reg [3:0] wregno_W;
	reg wrreg_W, rmem_W;
    always @(posedge clk) if(lock) begin
		{memout_W,	nonmem_W,	wregno_W,	wrreg_W	} <= {memout_M, nonmem_M, wregno_M, wrreg_M	};
		{rmem_W										} <= {rmem_M								};
	end

	//W Stage
	wire [(DBITS-1):0] regval_W = rmem_W?memout_W:nonmem_W;
	//Note that the code that connects the register write signals to the register
	//file is already there in the instantiation of the RegFile module (see above)
	
	
	//DEBUG CODE
	
	/*ALU_OUT with instruction
	SevenSeg ss3(.OUT(HEX3),.IN(SW[9]?inst_A[31:28]:aluout_A[15:12]));
    SevenSeg ss2(.OUT(HEX2),.IN(SW[9]?inst_A[27:24]:aluout_A[11: 8]));
    SevenSeg ss1(.OUT(HEX1),.IN(SW[9]?inst_A[23:20]:aluout_A[ 7: 4]));
    SevenSeg ss0(.OUT(HEX0),.IN(SW[9]?inst_A[19:16]:aluout_A[ 3: 0]));
	*/
	
	/*ALU_IN with instruction
	SevenSeg ss3(.OUT(HEX3),.IN(SW[9]?inst_A[31:28]:aluin1_A[15:12]));
    SevenSeg ss2(.OUT(HEX2),.IN(SW[9]?inst_A[27:24]:aluin1_A[11: 8]));
    SevenSeg ss1(.OUT(HEX1),.IN(SW[9]?inst_A[23:20]:aluin1_A[ 7: 4]));
    SevenSeg ss0(.OUT(HEX0),.IN(SW[9]?inst_A[19:16]:aluin1_A[ 3: 0]));
	*/
	
	
	/*PC_F and inst_F
	SevenSeg ss3(.OUT(HEX3),.IN(SW[9]?PC_F[31:28]:PC_F[15:12]));
    SevenSeg ss2(.OUT(HEX2),.IN(SW[9]?inst_F[27:24]:PC_F[11: 8]));
    SevenSeg ss1(.OUT(HEX1),.IN(SW[9]?inst_F[23:20]:PC_F[ 7: 4]));
    SevenSeg ss0(.OUT(HEX0),.IN(SW[9]?inst_F[19:16]:PC_F[ 3: 0]));
	*/
    
    /*inst_R and stuff
    
    SevenSeg ss3(.OUT(HEX3),.IN(SW[9]?inst_R[31:28]:4'b1111));
    SevenSeg ss2(.OUT(HEX2),.IN(SW[9]?inst_R[27:24]:regout1_R[11: 8]));
    SevenSeg ss1(.OUT(HEX1),.IN(SW[9]?inst_R[23:20]:regout1_R[ 7: 4]));
    SevenSeg ss0(.OUT(HEX0),.IN(SW[9]?inst_R[19:16]:regout1_R[ 3: 0]));
    */
    //disp mem stage stuff
    /*
    	SevenSeg ss3(.OUT(HEX3),.IN(SW[9]?memout_M[31:28]:memout_M[15:12]));
		SevenSeg ss2(.OUT(HEX2),.IN(SW[9]?memout_M[27:24]:memout_M[11: 8]));
		SevenSeg ss1(.OUT(HEX1),.IN(SW[9]?memout_M[23:20]:memout_M[ 7: 4]));
		SevenSeg ss0(.OUT(HEX0),.IN(SW[9]?memout_M[19:16]:memout_M[ 3: 0]));
    
    */
    
endmodule

module RegFile(RADDR1,DOUT1,RADDR2,DOUT2,WADDR,DIN,WE,CLK);
  parameter DBITS; // Number of data bits
  parameter ABITS; // Number of address bits
  parameter WORDS = (1<<ABITS);
  parameter MFILE = "";
  (* ram_init_file = MFILE *)
  reg [(DBITS-1):0] mem[(WORDS-1):0];
  input  [(ABITS-1):0] RADDR1,RADDR2,WADDR;
  input  [(DBITS-1):0] DIN;
  output wire [(DBITS-1):0] DOUT1,DOUT2;
  input CLK,WE;
  always @(posedge CLK)
    if(WE)
      mem[WADDR]=DIN;
  assign DOUT1=(WE&&(WADDR==RADDR1))?DIN:mem[RADDR1];
  assign DOUT2=(WE&&(WADDR==RADDR2))?DIN:mem[RADDR2];
endmodule

module MemSys(IAddr,IOut,DAddr,DOut,DIn,DWE,CLK,KEY,SW,HEX0,HEX1,HEX2,HEX3);
  // File to initialize memory with
  parameter MFILE;
  // Number of bits in a memory word
  parameter DBITS;
  // Number of bits in the physical address
  parameter PABITS=DBITS;
  // Number of bits in the real address
  parameter RABITS;
  parameter RWORDS=(1<<(RABITS-2));
  input wire  [(PABITS-1):0] IAddr,DAddr;
  input wire  [(DBITS-1):0] DIn;
  input wire  DWE,CLK;
  output wire [(DBITS-1):0] IOut,DOut;
  input  wire [3:0] KEY;
  input  wire [9:0] SW;
  output wire [6:0] HEX0,HEX1,HEX2,HEX3;
  // Real memory
  (* ram_init_file = MFILE *) (* ramstyle="no_rw_check" *)
  reg [(DBITS-1):0] marray[RWORDS];
  // Hex display
  // Note how you can use SW[9] to see the upper 16 bits of
  // the 32-bit value written to the hex display I/O address
  reg [31:0] HexOut=31'h6789ABCD;
  SevenSeg ss3(.OUT(HEX3),.IN(SW[9]?HexOut[31:28]:HexOut[15:12]));
  SevenSeg ss2(.OUT(HEX2),.IN(SW[9]?HexOut[27:24]:HexOut[11: 8]));
  SevenSeg ss1(.OUT(HEX1),.IN(SW[9]?HexOut[23:20]:HexOut[ 7: 4]));
  SevenSeg ss0(.OUT(HEX0),.IN(SW[9]?HexOut[19:16]:HexOut[ 3: 0]));
  assign DOut=
    (DAddr[(PABITS-1):RABITS]=={(PABITS-RABITS){1'b0}})?marray[DAddr[(RABITS-1):2]]:
    (DAddr==32'hFFFFF000)?{28'b0,KEY}://SW[3:0]}://KEY}:
    (DAddr==32'hFFFFF004)?{22'b0,SW}:
    32'hXXXXXXXX;
  assign IOut=
    (IAddr[(PABITS-1):RABITS]=={(PABITS-RABITS){1'b0}})?marray[IAddr[(RABITS-1):2]]:
    32'hXXXXXXXX;
  always @(posedge CLK) begin
    if(DWE) begin
      if(DAddr[(PABITS-1):RABITS]=={(PABITS-RABITS){1'b0}})
        marray[DAddr[(RABITS-1):2]]=DIn;
      else if(DAddr==32'hFFFFF800)
        HexOut<=DIn[15:0];
    end
  end
endmodule

module SevenSeg(OUT, IN);
	output[6:0] OUT;
	input [7:0] IN;
	assign OUT=
		(IN == 4'd0) ? 7'b1000000 :
		(IN == 4'd1) ? 7'b1111001 :
		(IN == 4'd2) ? 7'b0100100 :
		(IN == 4'd3) ? 7'b0110000 :
		(IN == 4'd4) ? 7'b0011001 :
		(IN == 4'd5) ? 7'b0010010 :
		(IN == 4'd6) ? 7'b0000010 :
		(IN == 4'd7) ? 7'b1111000 :
		(IN == 4'd8) ? 7'b0000000 :
		(IN == 4'd9) ? 7'b0010000 :
		(IN == 4'd10) ? 7'b0001000 :
		(IN == 4'd11) ? 7'b0000011 :
		(IN == 4'd12) ? 7'b1000110 :
		(IN == 4'd13) ? 7'b0100001 :
		(IN == 4'd14) ? 7'b0000110 :
		(IN == 4'd15) ? 7'b0001110 :
					    7'b0110000 ;
					    
endmodule
